#pragma once

#include "tmlib.h"

template <int N, typename T = float>
class Vector
{
public :
    static const int        SIZE = N;

    typedef Vector<N, T>    ThisType;
    typedef T               ElementType;
    typedef T               ValueType;

public :
    Vector() {}
    Vector(ElementType& x) { set(x); }
    Vector(ElementType& x, ElementType& y) { set(x, y); }
    Vector(ElementType& x, ElementType& y, ElementType& z) { set(x, y, z); }

    ThisType& set(ElementType& x)
    {
        return x(x);
    }
    ThisType& set(ElementType& x, ElementType& y)
    {
        return x(x).y(y);
    }
    ThisType& set(ElementType& x, ElementType& y, ElementType& z)
    {
        return x(x).y(y).z(z);
    }

public :
    float length() { return ::length(*this); }

    const ElementType& operator()(int index) const { return _element[index]; }
    const ElementType& x() const { return _element[0]; }
    const ElementType& y() const { return _element[1]; }
    const ElementType& z() const { return _element[2]; }
    const ElementType& w() const { return _element[3]; }

    ThisType& operator()(int index, const ElementType& value) { _element[index] = value; return *this; }
    ThisType& x(const ElementType& x) { return (*this)(0, x); }
    ThisType& y(const ElementType& y) { return (*this)(1, y); }
    ThisType& z(const ElementType& z) { return (*this)(2, z); }
    ThisType& w(const ElementType& w) { return (*this)(3, w); }

private :
    ElementType _element[SIZE];
};

template <int N, typename T>
static float length(const Vector<N, T>& v)
{
    float temp = 0;
    for (s32 i=0; i<N; ++i) { temp += v(i)*v(i); }
    return sqrt(temp);
}
template <typename T>
static float length(const Vector<1, T>& v) { return sqrt( v.x()*v.x() ); }
template <typename T>
static float length(const Vector<2, T>& v) { return sqrt( v.x()*v.x() + v.y()*v.y() ); }
template <typename T>
static float length(const Vector<3, T>& v) { return sqrt( v.x()*v.x() + v.y()*v.y() + v.z()*v.z() ); }

typedef Vector<2, float> Vector2f;
typedef Vector<3, float> Vector3f;
typedef Vector<4, float> Vector4f;
